//
//  MJRefreshComponent.swift
//  OC-Swift
//
//  Created by 陆文宇 on 2017/2/14.
//  Copyright © 2017年 陆文宇. All rights reserved.
//

import UIKit

class MJRefreshComponent: UIView {
    
    enum MJRefreshState: Int {
        case idle = 1
        case pulling = 2
        case refreshing = 3
        case willRefresh = 4
        case noMoreData = 5
    }
    
    typealias MJRefreshComponentRefreshingClosure = () -> Void
    typealias MJRefreshComponentbeginRefreshingCompletionClosure = () -> Void
    typealias MJRefreshComponentEndRefreshingCompletionClosure = () -> Void
    
    var refreshingClosure: MJRefreshComponentRefreshingClosure?

    var _state: MJRefreshState = .idle
    var state: MJRefreshState {
        set {
            _state = newValue
            
            DispatchQueue.main.async {
                self.setNeedsLayout()
            }
        }
        
        get {
            return _state
        }
    }
    var scrollViewOriginalInset: UIEdgeInsets?
    weak var scrollView: UIScrollView?
    private var pan: UIPanGestureRecognizer?
    var _pullingPercent: CGFloat?
    var pullingPercent: CGFloat? {
        set {
            guard !isRefreshing else {
                return
            }
            
            _pullingPercent = newValue
            
            if automaticallyChangeAlpha {
                alpha = newValue!
            }
        }
        
        get {
            return _pullingPercent
        }
    }
    var beginRefreshingCompletionClosure: MJRefreshComponentbeginRefreshingCompletionClosure?
    var endRefreshingCompletionClosure: MJRefreshComponentEndRefreshingCompletionClosure?
    var isRefreshing: Bool {
        return state == .refreshing || state == .willRefresh
    }
    var automaticallyChangeAlpha: Bool = false {
        willSet {
            guard !isRefreshing else {
                return
            }
            
            if newValue {
                alpha = pullingPercent!
            } else {
                alpha = 1.0;
            }
        }
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        prepare()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    func executeRefreshingCallback() -> Void {
        DispatchQueue.main.async {
            if self.refreshingClosure != nil {
                self.refreshingClosure!()
            }
            
            if self.beginRefreshingCompletionClosure != nil {
                self.beginRefreshingCompletionClosure!()
            }
        }
    }
    
    func endRefreshing(with completionClosure: @escaping MJRefreshComponentEndRefreshingCompletionClosure) -> Void {
        endRefreshingCompletionClosure = completionClosure
        
        endRefreshing()
    }
    
    func endRefreshing() -> Void {
        state = .idle
    }
    
    func beginRefreshing(with completionClosure: @escaping MJRefreshComponentbeginRefreshingCompletionClosure) -> Void {
        beginRefreshingCompletionClosure = completionClosure
        
        beginRefreshing()
    }
    
    func beginRefreshing() -> Void {
        UIView.animate(withDuration: MJRefreshFastAnimationDuration, animations: {
            self.alpha = 1
        })
        pullingPercent = 1
        if window != nil {
            state = .refreshing
        } else {
            if state != .refreshing {
                state = .willRefresh
                setNeedsDisplay()
            }
        }
    }
    
    func addObservers() -> Void {
        let options: NSKeyValueObservingOptions = [.new, .old]
        scrollView?.addObserver(self, forKeyPath: MJRefreshKeyPathContentOffset, options: options, context: nil)
        scrollView?.addObserver(self, forKeyPath: MJRefreshKeyPathContentSize, options: options, context: nil)
        pan = scrollView?.panGestureRecognizer
        pan?.addObserver(self, forKeyPath: MJRefreshKeyPathPanState, options: options, context: nil)
    }
    
    func removeObservers() -> Void {
        superview?.removeObserver(self, forKeyPath: MJRefreshKeyPathContentOffset)
        superview?.removeObserver(self, forKeyPath: MJRefreshKeyPathContentSize)
        pan?.removeObserver(self, forKeyPath: MJRefreshKeyPathPanState)
        pan = nil
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard isUserInteractionEnabled else {
            return
        }
        
        if keyPath == MJRefreshKeyPathContentSize {
            scrollViewContentSizeDidChange(change: change!)
        }
        
        guard !isHidden else {
            return
        }
        
        if keyPath == MJRefreshKeyPathContentOffset {
            scrollViewContentOffsetDidChange(change: change!)
        } else {
            scrollViewPanStateDidChange(change: change!)
        }
    }
    
    func scrollViewContentOffsetDidChange(change: Dictionary<NSKeyValueChangeKey, Any>) -> Void {
        
    }
    
    func scrollViewContentSizeDidChange(change: Dictionary<NSKeyValueChangeKey, Any>?) -> Void {
        
    }
    
    func scrollViewPanStateDidChange(change: Dictionary<NSKeyValueChangeKey, Any>) -> Void {
        
    }
    
    override func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview: newSuperview)
        
        if newSuperview != nil && !(newSuperview is UIScrollView)  {
            return
        }
        
        removeObservers()
        
        if let newSuperview = newSuperview {
            mj_w = newSuperview.mj_w
            mj_x = 0
            
            scrollView = newSuperview as? UIScrollView
            scrollView?.alwaysBounceVertical = true
            scrollViewOriginalInset = scrollView?.contentInset
            
            addObservers()
        }
    }
    
    override func layoutSubviews() {
        placeSubviews()
        
        super.layoutSubviews()
    }
    
    func placeSubviews() -> Void {
        
    }
    
    func prepare() -> Void {
        autoresizingMask = .flexibleWidth
        backgroundColor = UIColor.clear
    }
    

    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
        super.draw(rect)
        
        if state == .willRefresh {
            state = .refreshing
        }
    }
}

extension UILabel {
    
    var mj_textWith: CGFloat {
        var stringWidth: CGFloat = 0
        let size: CGSize = CGSize(width: CGFloat.infinity, height: CGFloat.infinity)
        if text != nil && text!.count > 0 {
            let nsText: NSString = NSString(string: text!)
            stringWidth = nsText.boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil).size.width
        }
        return stringWidth
    }
    
    static func mj_label() -> UILabel {
        let label: UILabel = UILabel()
        label.font = MJRefreshLabelFont
        label.textColor = MJRefreshLabelTextColor
        label.autoresizingMask = .flexibleWidth
        label.textAlignment = .center
        label.backgroundColor = UIColor.clear
        return label
    }
    
}
